#pragma once

#include "box/service_context.hh"
#include "util/singleton.hh"
#include "util/string_format.hpp"

namespace kratos {
namespace util {

struct LogHelper {
  kratos::service::ServiceContext *ctx{nullptr};
  kratos::service::ServiceLogger *log_ptr{nullptr};
};

} // namespace util
} // namespace kratos

#define slog_instance (kratos::Singleton<kratos::util::LogHelper>::instance())

#define slog_init(c) slog_instance->ctx = c;
#define slog_begin(m) slog_instance->log_ptr = m.get();
#define slog_end() slog_instance->log_ptr = nullptr;
#define slog_cleanup()                                                         \
  {                                                                            \
    slog_instance->ctx = nullptr;                                              \
    slog_instance->log_ptr = nullptr;                                          \
  }

#define slog_verb(...)                                                         \
  if (slog_instance->log_ptr) {                                                \
    slog_instance->log_ptr->verbose_log(sformat(__VA_ARGS__));                 \
  } else {                                                                     \
    if (slog_instance->ctx) {                                                  \
      slog_instance->ctx->verbose(sformat(__VA_ARGS__));                       \
    }                                                                          \
  }

#define slog_info(...)                                                         \
  if (slog_instance->log_ptr) {                                                \
    slog_instance->log_ptr->info_log(sformat(__VA_ARGS__));                    \
  } else {                                                                     \
    if (slog_instance->ctx) {                                                  \
      slog_instance->ctx->info(sformat(__VA_ARGS__));                          \
    }                                                                          \
  }

#define slog_debug(...)                                                        \
  if (slog_instance->log_ptr) {                                                \
    slog_instance->log_ptr->debug_log(sformat(__VA_ARGS__));                   \
  } else {                                                                     \
    if (slog_instance->ctx) {                                                  \
      slog_instance->ctx->diagnose(sformat(__VA_ARGS__));                      \
    }                                                                          \
  }

#define slog_warn(...)                                                         \
  if (slog_instance->log_ptr) {                                                \
    slog_instance->log_ptr->warn_log(sformat(__VA_ARGS__));                    \
  } else {                                                                     \
    if (slog_instance->ctx) {                                                  \
      slog_instance->ctx->warn(sformat(__VA_ARGS__));                          \
    }                                                                          \
  }

#define slog_except(...)                                                       \
  if (slog_instance->log_ptr) {                                                \
    slog_instance->log_ptr->execpt_log(sformat(__VA_ARGS__));                  \
  } else {                                                                     \
    if (slog_instance->ctx) {                                                  \
      slog_instance->ctx->except(sformat(__VA_ARGS__));                        \
    }                                                                          \
  }

#define slog_fail(...)                                                         \
  if (slog_instance->log_ptr) {                                                \
    slog_instance->log_ptr->fail_log(sformat(__VA_ARGS__));                    \
  } else {                                                                     \
    if (slog_instance->ctx) {                                                  \
      slog_instance->ctx->fail(sformat(__VA_ARGS__));                          \
    }                                                                          \
  }

#define slog_fatal(...)                                                        \
  if (slog_instance->log_ptr) {                                                \
    slog_instance->log_ptr->fatal_log(sformat(__VA_ARGS__));                   \
  } else {                                                                     \
    if (slog_instance->ctx) {                                                  \
      slog_instance->ctx->fatal(sformat(__VA_ARGS__));                         \
    }                                                                          \
  }
